﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;

namespace Beeldbankmvc.Models
{
    #region Models
    [PropertiesMustMatch("NewPassword", "ConfirmPassword", ErrorMessage = "De opgegeven wachtwoorden komen niet overeen.")]
    public class ChangePasswordModel
    {
        [Required(ErrorMessage = "Huidig wachtwoord is verplicht.")]
        [DataType(DataType.Password)]
        [DisplayName("Huidig wachtwoord")]
        public string OldPassword { get; set; }

        [Required(ErrorMessage = "Nieuw wachtwoord is verplicht.")]
        [ValidatePasswordLength]
        [DataType(DataType.Password)]
        [DisplayName("Nieuw wachtwoord")]
        public string NewPassword { get; set; }

        [Required(ErrorMessage = "Nieuw wachtwoord (controle) is verplicht.")]
        [DataType(DataType.Password)]
        [DisplayName("Bevestig nieuw wachtwoord")]
        public string ConfirmPassword { get; set; }
    }

    public class LogOnModel
    {
        [Required(ErrorMessage = "Gebruikersnaam is verplicht. Vul hier NIET uw emailadres in, maar uw gebruikersnaam.")]
        [DisplayName("Gebruikersnaam *")]
        public string UserName { get; set; }

        [Required(ErrorMessage = "Wachtwoord is verplicht.")]
        [DataType(DataType.Password)]
        [DisplayName("Wachtwoord *")]
        public string Password { get; set; }

        [DisplayName("Mij onthouden?")]
        public bool RememberMe { get; set; }
    }

    [PropertiesMustMatch("Password", "ConfirmPassword", ErrorMessage = "De opgegeven wachtwoorden komen niet overeen.")]
    public class RegisterModel
    {
        [Required(ErrorMessage = "Gebruikersnaam is verplicht.")]
        [StringLength(50, ErrorMessage = "Gebruikersnaam mag maximaal 50 karakters bevatten. Gebruik hier NIET uw emailadres.")]
        [DisplayName("Gebruikersnaam *")]
        public string UserName { get; set; }        

        [Required(ErrorMessage = "Emailadres is verplicht")]
        [RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Vul a.u.b. een geldig emailadres in.")]
        [DisplayName("Emailadres *")]
        public string Email { get; set; }

        [Required(ErrorMessage = "Wachtwoord is verplicht.")]
        [RegularExpression(@"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{7,}$", ErrorMessage = "Het opgegeven wachtwoord is niet complex genoeg.")]
        [DataType(DataType.Password)]
        [DisplayName("Wachtwoord *")]
        public string Password { get; set; }

        [Required(ErrorMessage = "Nieuw wachtwoord (controle) is verplicht.")]
        [DataType(DataType.Password)]
        [DisplayName("Bevestig wachtwoord *")]
        public string ConfirmPassword { get; set; }

        [Required]
        [BooleanMustBeTrue(ErrorMessage = "Het accepteren van de voorwaarden is verplicht.")]
        [DisplayName("Algemene voorwaarden *")]
        public bool Agreement { get; set; }
    }

    // custom validation
    // http://www.diaryofaninja.com/blog/2011/01/20/required-checkbox-validation-in-aspnet-mvc-2-onwards
    //
    public class BooleanMustBeTrueAttribute : ValidationAttribute
    {
        public override bool IsValid(object propertyValue)
        {
            return propertyValue != null
                && propertyValue is bool
                && (bool)propertyValue;
        }
    }


    public class EnhancedAccountModel
    {
        public static IList<SelectListItem> headerList()
        {
            IList<SelectListItem> itemList = new List<SelectListItem>();
            itemList.Add(new SelectListItem { Text = "Dhr.", Value = "1" });
            itemList.Add(new SelectListItem { Text = "Mvr.", Value = "2" });

            return itemList;
        }

        public static IList<SelectListItem> countryList()
        {
            IList<SelectListItem> itemList = new List<SelectListItem>();
            itemList.Add(new SelectListItem { Text = "Maak keuze", Value = "0" });
            itemList.Add(new SelectListItem { Text = "NL", Value = "1" });
            itemList.Add(new SelectListItem { Text = "BE", Value = "2" });
            itemList.Add(new SelectListItem { Text = "DE", Value = "3" });
            itemList.Add(new SelectListItem { Text = "Anders", Value = "4" });

            return itemList;
        }

        public Guid UserId { get; set; }

        //[Required]
        [DataType(DataType.Text)]
        [DisplayName("Aanhef")]
        public string Header { get; set; }

        [Required(ErrorMessage = "Voornaam is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Voornaam *")]
        public string FirstName { get; set; }
                
        [DataType(DataType.Text)]
        [DisplayName("Tussenvoegsel")]
        public string Prepositions { get; set; }

        [Required(ErrorMessage = "Achternaam is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Achternaam *")]
        public string LastName { get; set; }

        [Required(ErrorMessage = "Telefoonnummer is verplicht.")]
        [DataType(DataType.PhoneNumber)]
        [DisplayName("Telefoonnummer *")]
        public string Phone { get; set; }

        [Required(ErrorMessage = "Adres is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Adres *")]
        public string Address { get; set; }

        [Required(ErrorMessage = "Huisnummer is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Huisnummer *")]
        public string AddressNr { get; set; }

        [Required(ErrorMessage = "Postcode is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Postcode *")]
        public string ZipCode { get; set; }

        [Required(ErrorMessage = "Woonplaats is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Woonplaats *")]
        public string City { get; set; }

        //[Required]
        [DataType(DataType.Text)]
        [DisplayName("Land")]
        public string Country { get; set; }

        [DataType(DataType.Text)]
        [DisplayName("Bedrijfsnaam")]
        public string CompanyName { get; set; }

        // Factuur address(optional)
        [DataType(DataType.Text)]
        [DisplayName("Adres")]
        public string FactuurAddress { get; set; }

        [DataType(DataType.Text)]
        [DisplayName("Huisnummer")]
        public string FactuurAddressNr { get; set; }

        [DataType(DataType.Text)]
        [DisplayName("Postcode")]
        public string FactuurZipCode { get; set; }

        [DataType(DataType.Text)]
        [DisplayName("Woonplaats")]
        public string FactuurCity { get; set; }

        [DataType(DataType.Text)]
        [DisplayName("Land")]
        public string FactuurLand { get; set; }

    }

    public class EditAccountModel
    {
        public static IList<SelectListItem> headerList()
        {
            IList<SelectListItem> itemList = new List<SelectListItem>();
            itemList.Add(new SelectListItem { Text = "Dhr.", Value = "1" });
            itemList.Add(new SelectListItem { Text = "Mvr.", Value = "2" });

            return itemList;
        }

        public static IList<SelectListItem> countryList()
        {
            IList<SelectListItem> itemList = new List<SelectListItem>();
            itemList.Add(new SelectListItem { Text = "Maak keuze", Value = "0" });
            itemList.Add(new SelectListItem { Text = "NL", Value = "1" });
            itemList.Add(new SelectListItem { Text = "BE", Value = "2" });
            itemList.Add(new SelectListItem { Text = "DE", Value = "3" });
            itemList.Add(new SelectListItem { Text = "Anders", Value = "4" });

            return itemList;
        }

        public Guid UserId { get; set; }

        //[Required]
        [DataType(DataType.Text)]
        [DisplayName("Aanhef")]
        public string Header { get; set; }

        [Required(ErrorMessage = "Voornaam is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Voornaam *")]
        public string FirstName { get; set; }

        [DataType(DataType.Text)]
        [DisplayName("Tussenvoegsel")]
        public string Prepositions { get; set; }

        [Required(ErrorMessage = "Achternaam is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Achternaam *")]
        public string LastName { get; set; }

        [Required(ErrorMessage = "Emailadres is verplicht.")]
        [RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",ErrorMessage="Vul a.u.b. een geldig emailadres in.")]
        [DisplayName("Emailadres *")]
        public string Email { get; set; }

        [Required(ErrorMessage = "Telefoonnummer is verplicht.")]
        [DataType(DataType.PhoneNumber)]
        [DisplayName("Telefoonnummer *")]
        public string Phone { get; set; }

        [Required(ErrorMessage = "Adres is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Adres *")]
        public string Address { get; set; }

        [Required(ErrorMessage = "Huisnummer is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Huisnummer *")]
        public string AddressNr { get; set; }

        [Required(ErrorMessage = "Postcode is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Postcode *")]
        public string ZipCode { get; set; }

        [Required(ErrorMessage = "Woonplaats is verplicht.")]
        [DataType(DataType.Text)]
        [DisplayName("Woonplaats *")]
        public string City { get; set; }

        //[Required]
        [DataType(DataType.Text)]
        [DisplayName("Land")]
        public string Country { get; set; }

        [DataType(DataType.Text)]
        [DisplayName("Bedrijfsnaam")]
        public string CompanyName { get; set; }

        // Factuur address(optional)
        [DataType(DataType.Text)]
        [DisplayName("Adres")]
        public string FactuurAddress { get; set; }

        [DataType(DataType.Text)]
        [DisplayName("Huisnummer")]
        public string FactuurAddressNr { get; set; }

        [DataType(DataType.Text)]
        [DisplayName("Postcode")]
        public string FactuurZipCode { get; set; }

        [DataType(DataType.Text)]
        [DisplayName("Woonplaats")]
        public string FactuurCity { get; set; }

        [DataType(DataType.Text)]
        [DisplayName("Land")]
        public string FactuurLand { get; set; }

    }

    public class PasswordForgottenModel
    {
        [Required(ErrorMessage = "Gebruikersnaam is verplicht.")]        
        [DisplayName("Gebruikersnaam")]
        public string UserName { get; set; }  

    }
    #endregion

    #region Services
    // The FormsAuthentication type is sealed and contains static members, so it is difficult to
    // unit test code that calls its members. The interface and helper class below demonstrate
    // how to create an abstract wrapper around such a type in order to make the AccountController
    // code unit testable.

    public interface IMembershipService
    {
        int MinPasswordLength { get; }

        bool ValidateUser(string userName, string password);
        MembershipCreateStatus CreateUser(string userName, string password, string email);
        bool ChangePassword(string userName, string oldPassword, string newPassword);
    }

    public class AccountMembershipService : IMembershipService
    {
        private readonly MembershipProvider _provider;

        public AccountMembershipService()
            : this(null)
        {
        }

        public AccountMembershipService(MembershipProvider provider)
        {
            _provider = provider ?? Membership.Provider;
        }

        public int MinPasswordLength
        {
            get
            {
                return _provider.MinRequiredPasswordLength;
            }
        }

        public bool ValidateUser(string userName, string password)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Waarde kan niet null of leeg zijn.", "userName");
            if (String.IsNullOrEmpty(password)) throw new ArgumentException("Waarde kan niet null of leeg zijn.", "password");

            return _provider.ValidateUser(userName, password);
        }

        public MembershipCreateStatus CreateUser(string userName, string password, string email)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Waarde kan niet null of leeg zijn.", "userName");
            if (String.IsNullOrEmpty(password)) throw new ArgumentException("Waarde kan niet null of leeg zijn.", "password");
            if (String.IsNullOrEmpty(email)) throw new ArgumentException("Waarde kan niet null of leeg zijn.", "email");

            MembershipCreateStatus status;
            _provider.CreateUser(userName, password, email, null, null, true, null, out status);
            return status;
        }

        public bool ChangePassword(string userName, string oldPassword, string newPassword)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Waarde kan niet null of leeg zijn.", "userName");
            if (String.IsNullOrEmpty(oldPassword)) throw new ArgumentException("Waarde kan niet null of leeg zijn.", "oldPassword");
            if (String.IsNullOrEmpty(newPassword)) throw new ArgumentException("Waarde kan niet null of leeg zijn.", "newPassword");

            // The underlying ChangePassword() will throw an exception rather
            // than return false in certain failure scenarios.
            try
            {
                MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */);
                return currentUser.ChangePassword(oldPassword, newPassword);
            }
            catch (ArgumentException)
            {
                return false;
            }
            catch (MembershipPasswordException)
            {
                return false;
            }
        }
    }

    public interface IFormsAuthenticationService
    {
        void SignIn(string userName, bool createPersistentCookie);
        void SignOut();
    }

    public class FormsAuthenticationService : IFormsAuthenticationService
    {
        public void SignIn(string userName, bool createPersistentCookie)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");

            FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
        }

        public void SignOut()
        {
            FormsAuthentication.SignOut();
        }
    }
    #endregion

    #region Validation
    public static class AccountValidation
    {
        public static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // See http://go.microsoft.com/fwlink/?LinkID=177550 for
            // a full list of status codes.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "Gebruikersnaam is al in gebruik. Kies a.u.b. een andere gebruikersnaam.";
                    //return "Username already exists. Please enter a different user name.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "Dit emailadres is al in gebruik. Vul a.u.b. een ander emailadres in.";
                    //return "A username for that e-mail address already exists. Please enter a different e-mail address.";

                case MembershipCreateStatus.InvalidPassword:
                    return "Het opgegeven wachtwoord is ongeldig. Geef a.u.b. een geldig wachtwoord op.";
                    //return "The password provided is invalid. Please enter a valid password value.";

                case MembershipCreateStatus.InvalidEmail:
                    return "Het opgegeven emailadres is ongeldig. Vul a.u.b. een geldig emailadres in.";
                    //return "The e-mail address provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidAnswer:                    
                    return "The password retrieval answer provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "The password retrieval question provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidUserName:
                    return "De opgegeven gebruikersnaam is ongeldig. Controleer de gebruikersnaam en probeer het opnieuw.";
                    //return "The user name provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.ProviderError:
                    return "De authentication provider heeft een foutmelding gegenereerd. Controleer uw invoer en probeer het opnieuw. Neem contact op met uw systeembeheerder als het probleem aanhoudt.";
                    //return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                case MembershipCreateStatus.UserRejected:
                    return "Het aanmaken van de nieuwe gebruiker is geannuleerd. Controleer uw invoer en probeer het opnieuw. Neem contact op met uw systeembeheerder als het probleem aanhoudt.";
                    //return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                default:
                    return "Een onbekend probleem heeft zich voorgedaan. Controleer uw invoer en probeer het opnieuw. Neem contact op met uw systeembeheerder als het probleem aanhoudt.";
                    //return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
            }
        }
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public sealed class PropertiesMustMatchAttribute : ValidationAttribute
    {
        //private const string _defaultErrorMessage = "'{0}' and '{1}' do not match.";
        private const string _defaultErrorMessage = "'{0}' en '{1}' komen niet overeen.";
        private readonly object _typeId = new object();

        public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty)
            : base(_defaultErrorMessage)
        {
            OriginalProperty = originalProperty;
            ConfirmProperty = confirmProperty;
        }

        public string ConfirmProperty { get; private set; }
        public string OriginalProperty { get; private set; }

        public override object TypeId
        {
            get
            {
                return _typeId;
            }
        }

        public override string FormatErrorMessage(string name)
        {
            return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
                OriginalProperty, ConfirmProperty);
        }

        public override bool IsValid(object value)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
            object originalValue = properties.Find(OriginalProperty, true /* ignoreCase */).GetValue(value);
            object confirmValue = properties.Find(ConfirmProperty, true /* ignoreCase */).GetValue(value);
            return Object.Equals(originalValue, confirmValue);
        }
    }

    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public sealed class ValidatePasswordLengthAttribute : ValidationAttribute
    {
        //private const string _defaultErrorMessage = "'{0}' must be at least {1} characters long.";
        private const string _defaultErrorMessage = "'{0}' dient ten minste {1} karakters te bevatten.";
        private readonly int _minCharacters = Membership.Provider.MinRequiredPasswordLength;

        public ValidatePasswordLengthAttribute()
            : base(_defaultErrorMessage)
        {
        }

        public override string FormatErrorMessage(string name)
        {
            return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
                name, _minCharacters);
        }

        public override bool IsValid(object value)
        {
            string valueAsString = value as string;
            return (valueAsString != null && valueAsString.Length >= _minCharacters);
        }
    }
    #endregion

}
